/*
 *  Index.h
 *  Rempart
 *
 *
 */

#ifndef __INDEX
#define __INDEX

#include "MapElement.h"

extern sf::Mutex globalLock;



template <class T>
class Index {
   
public:

	Index(bool enableIDManagement=1);
	~Index();
	
	T getObjectAt(int index);
	MapElement* getMapElementAt(int index);
	sf::Vector2<float> getObjectPositionAt(int index);
	sf::Vector2<int> getObjectMapPositionAt(int index);
	
	
	
	void deleteObjectAt(int index);
	void deleteAllObjects();
	void addObject(T object);
	void addMapElement(MapElement* object);
	int size();
	void clear();
	void removeObjectAt(int index);
	
private:
	bool idManagement;
	std::vector<T>* array;
	sf::Mutex arrayLock;
	
	
};




/*
 * IMPLEMENTATION
 * Index étant un template, impossible de le mettre dans un fichier .cpp.
 */


template <class T>
Index<T>::Index(bool enableIDManagement){
	this->idManagement=enableIDManagement;
	this->array = new std::vector<T>;
	
}
template <class T>
Index<T>::~Index(){
	this->clear();
}
template <class T>
T Index<T>::getObjectAt(int index){
	this->arrayLock.Lock();
	T myObject =this->array->at(index);
	this->arrayLock.Unlock();
	return myObject;
}

template <class T>
MapElement* Index<T>::getMapElementAt(int index){
	return (MapElement*) this->getObjectAt(index);
}

template <class T>
sf::Vector2<float> Index<T>::getObjectPositionAt(int index){
	return this->getObjectAt(index)->GetPosition();
	
}

template <class T>
sf::Vector2<int> Index<T>::getObjectMapPositionAt(int index){
	sf::Vector2<int> position((this->getObjectPositionAt(index).x)/MapElement::getWidth(), (this->getObjectPositionAt(index).y)/MapElement::getHeigth());
	return position;
	
}

template <class T>
void Index<T>::removeObjectAt(int index){
	if (this->size() > 0) {
		if (this->idManagement) {
			for (int i = this->array->size()-1; i >= index; i--) {
				this->getMapElementAt(i)->setId(this->getMapElementAt(i)->getId()-1);
			}
		}
		this->arrayLock.Lock();
		this->array->erase(this->array->begin()+index);
		this->arrayLock.Unlock();
		
	}
}



template <class T>
void Index<T>::deleteObjectAt(int index){
	if (this->size() > 0) {
		if (this->idManagement) {
			for (int i = this->array->size()-1; i >= index; i--) {
				this->getMapElementAt(i)->setId(this->getMapElementAt(i)->getId()-1);
			}
		}
		
		T myObject = this->getObjectAt(index);
		this->arrayLock.Lock();
		this->array->erase(this->array->begin()+index);
		delete myObject;
		this->arrayLock.Unlock();
		
	}
}

template <class T>
void Index<T>::deleteAllObjects(){
	if (this->size() > 0) {

		for (int i = this->array->size() - 1; i >=0; i--) {
			this->deleteObjectAt(i);
		}
	}
}

template <class T>
void Index<T>::addObject(T object){
	this->arrayLock.Lock();
	this->array->push_back(object);
	if (this->idManagement) {
		this->array->back()->setId(this->array->size() - 1);
	}
	this->arrayLock.Unlock();
}

template <class T>
void Index<T>::addMapElement(MapElement* object){
	this->addObject((T)object);
}

template <class T>
int Index<T>::size(){
	this->arrayLock.Lock();
	int mySize = (int) this->array->size();
	this->arrayLock.Unlock();
	return mySize;
}

template <class T>
void Index<T>::clear(){
	this->arrayLock.Lock();
	this->array->clear();
	this->arrayLock.Unlock();
}

#endif